package com.heima.mobile.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.dto.PhoneCodeDto;
import com.heima.mapper.UserMapper;
import com.heima.mobile.service.UserService;
import com.heima.pojo.User;
import com.heima.vo.LoginVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.Duration;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author itheima
 * @since 2022-11-28
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public Boolean sendMsg(String phone) {

        // 1.生成验证码
        // 0~ 99999
        int number = new Random().nextInt(100000) + 100000;

        log.info("验证码：" + number);

        // 2. 将验证码写入到Redis
        // 2.1 导入Redis坐标依赖
        // 2.2 检查Redis配置
        // 2.3 启动本地的Redis服务
        // 2.4 注入 RedisTemplate
        // 2.5 通过 redisTemplate.opsForValue().set() 写入数据

        redisTemplate.opsForValue().set("CODE" + phone, number + "", 2L, TimeUnit.HOURS);

        // 另外一种过期时间设置方式
        // redisTemplate.expire("", Duration.ofDays(2));

        // 3. 发送验证码

        return true;
    }

    @Autowired
    private UserMapper userMapper;

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public LoginVo login(PhoneCodeDto dto) {
        // 1. 校验入参
        if (dto == null || StringUtils.isEmpty(dto.getCode()) || StringUtils.isEmpty(dto.getPhone())) {
            throw new RuntimeException("入参不能为空");
        }

        String phone = dto.getPhone();

        // 2. 校验验证码
        // 2.1 从redis读取之前发送的验证码
        String codeFromRedis = redisTemplate.opsForValue().get("CODE" + phone);
        if (StringUtils.isEmpty(codeFromRedis)) {
            throw new RuntimeException("验证码为空");
        }

        // 2.2 从dto中获取用户提交的验证码
        String code = dto.getCode();

        // 2.3 比对两个验证码
        if (!codeFromRedis.equals(code)) {
            throw new RuntimeException("验证码不正确");
        }

        // 3. 检测手机号是否存在
        // 3.1 创建user的实体类和mapper
        // 3.2 调用UserMapper.selectByPhone方法
        User user = userMapper.selectByPhone(phone);
        // 5. 如果不存在，则创建账号，生成token，写入redis
        if (user == null) {
            // 5.1 组装User对象
            User newUser = new User();
            newUser.setPhone(phone);
            newUser.setName("用户" + System.currentTimeMillis());
            newUser.setSex("");
            newUser.setAvatar("");
            newUser.setIdNumber("");
            newUser.setStatus(1);

            // 5.2 调用userMapper.insert
            int insertResult = userMapper.insert(newUser);
            if (insertResult != 1) {
                throw new RuntimeException("新用户注册失败");
            }

            user = new User();

            // 5.3 把当前创建好的新用户信息，赋值到user对象中
            BeanUtils.copyProperties(newUser, user);
        }

        // 4. 如果存在，则生成token，写入Redis
        // 4.1 生成 token（无规则、唯一、有过期时间的）
        String token = "reggie_" + System.currentTimeMillis();

        // 4.2 将token存储到Redis里面
        // 目的：通过token可以找到 token对应的用户信息
        // 注意：如果你想把一个对象 存到Redis的话，那么最好先转成json再存进去
        // fastJson
        redisTemplate.opsForValue().set(token, JSON.toJSONString(user), 7L, TimeUnit.DAYS);

        // 4.3 组装返回值的vo结构
        LoginVo vo = new LoginVo();
        vo.setId(user.getId());
        vo.setPhone(user.getPhone());
        vo.setStatus(user.getStatus());
        vo.setToken(token);

        return vo;
    }
}
